diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 8d11499d2..1019a708a 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -843,7 +843,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (serverMsgId == null) { serverMsgId = extractStanzaId(account, packet); } - mXmppConnectionService.getJingleConnectionManager().deliverMessage(account, packet.getTo(), packet.getFrom(), child, serverMsgId, timestamp); + mXmppConnectionService.getJingleConnectionManager().deliverMessage(account, packet.getTo(), packet.getFrom(), child, remoteMsgId, serverMsgId, timestamp); } else if (query.isCatchup()) { final String sessionId = child.getAttribute("id"); if (sessionId == null) { diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java index b4ee00ca7..56b622a92 100644 --- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java @@ -74,7 +74,8 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe private static final List END_CARD = Arrays.asList( RtpEndUserState.APPLICATION_ERROR, RtpEndUserState.DECLINED_OR_BUSY, - RtpEndUserState.CONNECTIVITY_ERROR + RtpEndUserState.CONNECTIVITY_ERROR, + RtpEndUserState.RETRACTED ); private static final String PROXIMITY_WAKE_LOCK_TAG = "conversations:in-rtp-session"; private static final int REQUEST_ACCEPT_CALL = 0x1111; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java index 99da9fa18..4b1fd5a36 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/AbstractJingleConnection.java @@ -113,6 +113,7 @@ public abstract class AbstractJingleConnection { PROCEED, REJECTED, RETRACTED, + RETRACTED_RACED, //used when receiving a retract after we already asked to proceed SESSION_INITIALIZED, //equal to 'PENDING' SESSION_INITIALIZED_PRE_APPROVED, SESSION_ACCEPTED, //equal to 'ACTIVE' diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index e4abcd27e..682d9bc9a 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -154,7 +154,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { account.getXmppConnection().sendIqPacket(response, null); } - public void deliverMessage(final Account account, final Jid to, final Jid from, final Element message, String serverMsgId, long timestamp) { + public void deliverMessage(final Account account, final Jid to, final Jid from, final Element message, String remoteMsgId, String serverMsgId, long timestamp) { Preconditions.checkArgument(Namespace.JINGLE_MESSAGE.equals(message.getNamespace())); final String sessionId = message.getAttribute("id"); if (sessionId == null) { @@ -174,6 +174,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { return; } final boolean fromSelf = from.asBareJid().equals(account.getJid().asBareJid()); + final boolean addressedDirectly = to != null && to.equals(account.getJid()); final AbstractJingleConnection.Id id; if (fromSelf) { if (to != null && to.isFullJid()) { @@ -250,7 +251,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { } else { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to react to proposed session with " + rtpDescriptions.size() + " rtp descriptions of " + descriptions.size() + " total descriptions"); } - } else if ("proceed".equals(message.getName())) { + } else if (addressedDirectly && "proceed".equals(message.getName())) { synchronized (rtpSessionProposals) { final RtpSessionProposal proposal = getRtpSessionProposal(account, from.asBareJid(), sessionId); if (proposal != null) { @@ -262,10 +263,21 @@ public class JingleConnectionManager extends AbstractConnectionManager { rtpConnection.deliveryMessage(from, message, serverMsgId, timestamp); } else { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": no rtp session proposal found for " + from + " to deliver proceed"); - //TODO return error message "item-not-found" + if (remoteMsgId == null) { + return; + } + final MessagePacket errorMessage = new MessagePacket(); + errorMessage.setTo(from); + errorMessage.setId(remoteMsgId); + errorMessage.setType(MessagePacket.TYPE_ERROR); + final Element error = errorMessage.addChild("error"); + error.setAttribute("code", "404"); + error.setAttribute("type", "cancel"); + error.addChild("item-not-found", "urn:ietf:params:xml:ns:xmpp-stanzas"); + mXmppConnectionService.sendMessagePacket(account, errorMessage); } } - } else if ("reject".equals(message.getName())) { + } else if (addressedDirectly && "reject".equals(message.getName())) { final RtpSessionProposal proposal = new RtpSessionProposal(account, from.asBareJid(), sessionId); synchronized (rtpSessionProposals) { if (rtpSessionProposals.remove(proposal) != null) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java index 3e66a219f..97de5b3c1 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -61,6 +61,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web State.ACCEPTED, State.REJECTED, State.RETRACTED, + State.RETRACTED_RACED, State.TERMINATED_SUCCESS, State.TERMINATED_DECLINED_OR_BUSY, State.TERMINATED_CONNECTIVITY_ERROR, @@ -86,6 +87,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web State.TERMINATED_CONNECTIVITY_ERROR //only used when the xmpp connection rebinds )); transitionBuilder.put(State.PROCEED, ImmutableList.of( + State.RETRACTED_RACED, State.SESSION_INITIALIZED_PRE_APPROVED, State.TERMINATED_SUCCESS, State.TERMINATED_APPLICATION_FAILURE, @@ -486,7 +488,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web } void deliverFailedProceed() { - //TODO do we want a special State.ITEM_NOT_FOUND to track retracted calls during network outages Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": receive message error for proceed message"); if (transition(State.TERMINATED_CONNECTIVITY_ERROR)) { webRTCWrapper.close(); @@ -617,14 +618,17 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web private void receiveRetract(final Jid from, final String serverMsgId, final long timestamp) { if (from.equals(id.with)) { - if (transition(State.RETRACTED)) { + final State target = this.state == State.PROCEED ? State.RETRACTED_RACED : State.RETRACTED; + if (transition(target)) { xmppConnectionService.getNotificationService().cancelIncomingCallNotification(); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": session with " + id.with + " has been retracted (serverMsgId=" + serverMsgId + ")"); if (serverMsgId != null) { this.message.setServerMsgId(serverMsgId); } this.message.setTime(timestamp); - this.message.markUnread(); + if (target == State.RETRACTED) { + this.message.markUnread(); + } writeLogMessageMissed(); finish(); } else { @@ -811,6 +815,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web case RETRACTED: case TERMINATED_CANCEL_OR_TIMEOUT: return RtpEndUserState.ENDED; + case RETRACTED_RACED: + return RtpEndUserState.RETRACTED; case TERMINATED_CONNECTIVITY_ERROR: return RtpEndUserState.CONNECTIVITY_ERROR; case TERMINATED_APPLICATION_FAILURE: