diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index ec90e294f..53d2d74b3 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -733,6 +733,18 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } } + public Message findRtpSession(final String sessionId, final int s) { + synchronized (this.messages) { + for (int i = this.messages.size() - 1; i >= 0; --i) { + final Message message = this.messages.get(i); + if ((message.getStatus() == s) && (message.getType() == Message.TYPE_RTP_SESSION) && sessionId.equals(message.getRemoteMsgId())) { + return message; + } + } + } + return null; + } + public boolean possibleDuplicate(final String serverMsgId, final String remoteMsgId) { if (serverMsgId == null || remoteMsgId == null) { return false; @@ -1007,7 +1019,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return UIHelper.getColorForName(getName().toString()); } - public interface OnMessageFound { + public interface OnMessageFound { void onMessageFound(final Message message); } diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index 3eb3c1aa6..41de4ec30 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -24,245 +24,248 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import rocks.xmpp.addr.Jid; public class MessageGenerator extends AbstractGenerator { - private static final String OMEMO_FALLBACK_MESSAGE = "I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo"; - private static final String PGP_FALLBACK_MESSAGE = "I sent you a PGP encrypted message but your client doesn’t seem to support that."; + private static final String OMEMO_FALLBACK_MESSAGE = "I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo"; + private static final String PGP_FALLBACK_MESSAGE = "I sent you a PGP encrypted message but your client doesn’t seem to support that."; - public MessageGenerator(XmppConnectionService service) { - super(service); - } + public MessageGenerator(XmppConnectionService service) { + super(service); + } - private MessagePacket preparePacket(Message message) { - Conversation conversation = (Conversation) message.getConversation(); - Account account = conversation.getAccount(); - MessagePacket packet = new MessagePacket(); - final boolean isWithSelf = conversation.getContact().isSelf(); - if (conversation.getMode() == Conversation.MODE_SINGLE) { - packet.setTo(message.getCounterpart()); - packet.setType(MessagePacket.TYPE_CHAT); - if (!isWithSelf) { - packet.addChild("request", "urn:xmpp:receipts"); - } - } else if (message.isPrivateMessage()) { - packet.setTo(message.getCounterpart()); - packet.setType(MessagePacket.TYPE_CHAT); - packet.addChild("x", "http://jabber.org/protocol/muc#user"); - packet.addChild("request", "urn:xmpp:receipts"); - } else { - packet.setTo(message.getCounterpart().asBareJid()); - packet.setType(MessagePacket.TYPE_GROUPCHAT); - } - if (conversation.isSingleOrPrivateAndNonAnonymous() && !message.isPrivateMessage()) { - packet.addChild("markable", "urn:xmpp:chat-markers:0"); - } - packet.setFrom(account.getJid()); - packet.setId(message.getUuid()); - packet.addChild("origin-id", Namespace.STANZA_IDS).setAttribute("id", message.getUuid()); - if (message.edited()) { - packet.addChild("replace", "urn:xmpp:message-correct:0").setAttribute("id", message.getEditedIdWireFormat()); - } - return packet; - } + private MessagePacket preparePacket(Message message) { + Conversation conversation = (Conversation) message.getConversation(); + Account account = conversation.getAccount(); + MessagePacket packet = new MessagePacket(); + final boolean isWithSelf = conversation.getContact().isSelf(); + if (conversation.getMode() == Conversation.MODE_SINGLE) { + packet.setTo(message.getCounterpart()); + packet.setType(MessagePacket.TYPE_CHAT); + if (!isWithSelf) { + packet.addChild("request", "urn:xmpp:receipts"); + } + } else if (message.isPrivateMessage()) { + packet.setTo(message.getCounterpart()); + packet.setType(MessagePacket.TYPE_CHAT); + packet.addChild("x", "http://jabber.org/protocol/muc#user"); + packet.addChild("request", "urn:xmpp:receipts"); + } else { + packet.setTo(message.getCounterpart().asBareJid()); + packet.setType(MessagePacket.TYPE_GROUPCHAT); + } + if (conversation.isSingleOrPrivateAndNonAnonymous() && !message.isPrivateMessage()) { + packet.addChild("markable", "urn:xmpp:chat-markers:0"); + } + packet.setFrom(account.getJid()); + packet.setId(message.getUuid()); + packet.addChild("origin-id", Namespace.STANZA_IDS).setAttribute("id", message.getUuid()); + if (message.edited()) { + packet.addChild("replace", "urn:xmpp:message-correct:0").setAttribute("id", message.getEditedIdWireFormat()); + } + return packet; + } - public void addDelay(MessagePacket packet, long timestamp) { - final SimpleDateFormat mDateFormat = new SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); - mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - Element delay = packet.addChild("delay", "urn:xmpp:delay"); - Date date = new Date(timestamp); - delay.setAttribute("stamp", mDateFormat.format(date)); - } + public void addDelay(MessagePacket packet, long timestamp) { + final SimpleDateFormat mDateFormat = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); + mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + Element delay = packet.addChild("delay", "urn:xmpp:delay"); + Date date = new Date(timestamp); + delay.setAttribute("stamp", mDateFormat.format(date)); + } - public MessagePacket generateAxolotlChat(Message message, XmppAxolotlMessage axolotlMessage) { - MessagePacket packet = preparePacket(message); - if (axolotlMessage == null) { - return null; - } - packet.setAxolotlMessage(axolotlMessage.toElement()); - packet.setBody(OMEMO_FALLBACK_MESSAGE); - packet.addChild("store", "urn:xmpp:hints"); - packet.addChild("encryption", "urn:xmpp:eme:0") - .setAttribute("name", "OMEMO") - .setAttribute("namespace", AxolotlService.PEP_PREFIX); - return packet; - } + public MessagePacket generateAxolotlChat(Message message, XmppAxolotlMessage axolotlMessage) { + MessagePacket packet = preparePacket(message); + if (axolotlMessage == null) { + return null; + } + packet.setAxolotlMessage(axolotlMessage.toElement()); + packet.setBody(OMEMO_FALLBACK_MESSAGE); + packet.addChild("store", "urn:xmpp:hints"); + packet.addChild("encryption", "urn:xmpp:eme:0") + .setAttribute("name", "OMEMO") + .setAttribute("namespace", AxolotlService.PEP_PREFIX); + return packet; + } - public MessagePacket generateKeyTransportMessage(Jid to, XmppAxolotlMessage axolotlMessage) { - MessagePacket packet = new MessagePacket(); - packet.setType(MessagePacket.TYPE_CHAT); - packet.setTo(to); - packet.setAxolotlMessage(axolotlMessage.toElement()); - packet.addChild("store", "urn:xmpp:hints"); - return packet; - } + public MessagePacket generateKeyTransportMessage(Jid to, XmppAxolotlMessage axolotlMessage) { + MessagePacket packet = new MessagePacket(); + packet.setType(MessagePacket.TYPE_CHAT); + packet.setTo(to); + packet.setAxolotlMessage(axolotlMessage.toElement()); + packet.addChild("store", "urn:xmpp:hints"); + return packet; + } - public MessagePacket generateChat(Message message) { - MessagePacket packet = preparePacket(message); - String content; - if (message.hasFileOnRemoteHost()) { - Message.FileParams fileParams = message.getFileParams(); - final URL url = fileParams.url; - if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) { - Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER); - final String file = url.getFile(); - x.setAttribute("name", file.charAt(0) == '/' ? file.substring(1) : file); - x.setAttribute("fileid", url.getHost()); - return packet; - } else { - content = url.toString(); - packet.addChild("x", Namespace.OOB).addChild("url").setContent(content); - } - } else { - content = message.getBody(); - } - packet.setBody(content); - return packet; - } + public MessagePacket generateChat(Message message) { + MessagePacket packet = preparePacket(message); + String content; + if (message.hasFileOnRemoteHost()) { + Message.FileParams fileParams = message.getFileParams(); + final URL url = fileParams.url; + if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) { + Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER); + final String file = url.getFile(); + x.setAttribute("name", file.charAt(0) == '/' ? file.substring(1) : file); + x.setAttribute("fileid", url.getHost()); + return packet; + } else { + content = url.toString(); + packet.addChild("x", Namespace.OOB).addChild("url").setContent(content); + } + } else { + content = message.getBody(); + } + packet.setBody(content); + return packet; + } - public MessagePacket generatePgpChat(Message message) { - MessagePacket packet = preparePacket(message); - if (message.hasFileOnRemoteHost()) { - Message.FileParams fileParams = message.getFileParams(); - final URL url = fileParams.url; - if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) { - Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER); - final String file = url.getFile(); - x.setAttribute("name", file.charAt(0) == '/' ? file.substring(1) : file); - x.setAttribute("fileid", url.getHost()); - } else { - packet.setBody(url.toString()); - packet.addChild("x", Namespace.OOB).addChild("url").setContent(url.toString()); - } - } else { - if (Config.supportUnencrypted()) { - packet.setBody(PGP_FALLBACK_MESSAGE); - } - if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { - packet.addChild("x", "jabber:x:encrypted").setContent(message.getEncryptedBody()); - } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { - packet.addChild("x", "jabber:x:encrypted").setContent(message.getBody()); - } - packet.addChild("encryption", "urn:xmpp:eme:0") - .setAttribute("namespace", "jabber:x:encrypted"); - } - return packet; - } + public MessagePacket generatePgpChat(Message message) { + MessagePacket packet = preparePacket(message); + if (message.hasFileOnRemoteHost()) { + Message.FileParams fileParams = message.getFileParams(); + final URL url = fileParams.url; + if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) { + Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER); + final String file = url.getFile(); + x.setAttribute("name", file.charAt(0) == '/' ? file.substring(1) : file); + x.setAttribute("fileid", url.getHost()); + } else { + packet.setBody(url.toString()); + packet.addChild("x", Namespace.OOB).addChild("url").setContent(url.toString()); + } + } else { + if (Config.supportUnencrypted()) { + packet.setBody(PGP_FALLBACK_MESSAGE); + } + if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { + packet.addChild("x", "jabber:x:encrypted").setContent(message.getEncryptedBody()); + } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { + packet.addChild("x", "jabber:x:encrypted").setContent(message.getBody()); + } + packet.addChild("encryption", "urn:xmpp:eme:0") + .setAttribute("namespace", "jabber:x:encrypted"); + } + return packet; + } - public MessagePacket generateChatState(Conversation conversation) { - final Account account = conversation.getAccount(); - MessagePacket packet = new MessagePacket(); - packet.setType(conversation.getMode() == Conversation.MODE_MULTI ? MessagePacket.TYPE_GROUPCHAT : MessagePacket.TYPE_CHAT); - packet.setTo(conversation.getJid().asBareJid()); - packet.setFrom(account.getJid()); - packet.addChild(ChatState.toElement(conversation.getOutgoingChatState())); - packet.addChild("no-store", "urn:xmpp:hints"); - packet.addChild("no-storage", "urn:xmpp:hints"); //wrong! don't copy this. Its *store* - return packet; - } + public MessagePacket generateChatState(Conversation conversation) { + final Account account = conversation.getAccount(); + MessagePacket packet = new MessagePacket(); + packet.setType(conversation.getMode() == Conversation.MODE_MULTI ? MessagePacket.TYPE_GROUPCHAT : MessagePacket.TYPE_CHAT); + packet.setTo(conversation.getJid().asBareJid()); + packet.setFrom(account.getJid()); + packet.addChild(ChatState.toElement(conversation.getOutgoingChatState())); + packet.addChild("no-store", "urn:xmpp:hints"); + packet.addChild("no-storage", "urn:xmpp:hints"); //wrong! don't copy this. Its *store* + return packet; + } - public MessagePacket confirm(final Account account, final Jid to, final String id, final Jid counterpart, final boolean groupChat) { - MessagePacket packet = new MessagePacket(); - packet.setType(groupChat ? MessagePacket.TYPE_GROUPCHAT : MessagePacket.TYPE_CHAT); - packet.setTo(groupChat ? to.asBareJid() : to); - packet.setFrom(account.getJid()); - Element displayed = packet.addChild("displayed", "urn:xmpp:chat-markers:0"); - displayed.setAttribute("id", id); - if (groupChat && counterpart != null) { - displayed.setAttribute("sender", counterpart.toString()); - } - packet.addChild("store", "urn:xmpp:hints"); - return packet; - } + public MessagePacket confirm(final Account account, final Jid to, final String id, final Jid counterpart, final boolean groupChat) { + MessagePacket packet = new MessagePacket(); + packet.setType(groupChat ? MessagePacket.TYPE_GROUPCHAT : MessagePacket.TYPE_CHAT); + packet.setTo(groupChat ? to.asBareJid() : to); + packet.setFrom(account.getJid()); + Element displayed = packet.addChild("displayed", "urn:xmpp:chat-markers:0"); + displayed.setAttribute("id", id); + if (groupChat && counterpart != null) { + displayed.setAttribute("sender", counterpart.toString()); + } + packet.addChild("store", "urn:xmpp:hints"); + return packet; + } - public MessagePacket conferenceSubject(Conversation conversation, String subject) { - MessagePacket packet = new MessagePacket(); - packet.setType(MessagePacket.TYPE_GROUPCHAT); - packet.setTo(conversation.getJid().asBareJid()); - packet.addChild("subject").setContent(subject); - packet.setFrom(conversation.getAccount().getJid().asBareJid()); - return packet; - } + public MessagePacket conferenceSubject(Conversation conversation, String subject) { + MessagePacket packet = new MessagePacket(); + packet.setType(MessagePacket.TYPE_GROUPCHAT); + packet.setTo(conversation.getJid().asBareJid()); + packet.addChild("subject").setContent(subject); + packet.setFrom(conversation.getAccount().getJid().asBareJid()); + return packet; + } - public MessagePacket directInvite(final Conversation conversation, final Jid contact) { - MessagePacket packet = new MessagePacket(); - packet.setType(MessagePacket.TYPE_NORMAL); - packet.setTo(contact); - packet.setFrom(conversation.getAccount().getJid()); - Element x = packet.addChild("x", "jabber:x:conference"); - x.setAttribute("jid", conversation.getJid().asBareJid().toString()); - String password = conversation.getMucOptions().getPassword(); - if (password != null) { - x.setAttribute("password", password); - } - if (contact.isFullJid()) { - packet.addChild("no-store", "urn:xmpp:hints"); - packet.addChild("no-copy", "urn:xmpp:hints"); - } - return packet; - } + public MessagePacket directInvite(final Conversation conversation, final Jid contact) { + MessagePacket packet = new MessagePacket(); + packet.setType(MessagePacket.TYPE_NORMAL); + packet.setTo(contact); + packet.setFrom(conversation.getAccount().getJid()); + Element x = packet.addChild("x", "jabber:x:conference"); + x.setAttribute("jid", conversation.getJid().asBareJid().toString()); + String password = conversation.getMucOptions().getPassword(); + if (password != null) { + x.setAttribute("password", password); + } + if (contact.isFullJid()) { + packet.addChild("no-store", "urn:xmpp:hints"); + packet.addChild("no-copy", "urn:xmpp:hints"); + } + return packet; + } - public MessagePacket invite(Conversation conversation, Jid contact) { - MessagePacket packet = new MessagePacket(); - packet.setTo(conversation.getJid().asBareJid()); - packet.setFrom(conversation.getAccount().getJid()); - Element x = new Element("x"); - x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user"); - Element invite = new Element("invite"); - invite.setAttribute("to", contact.asBareJid().toString()); - x.addChild(invite); - packet.addChild(x); - return packet; - } + public MessagePacket invite(Conversation conversation, Jid contact) { + MessagePacket packet = new MessagePacket(); + packet.setTo(conversation.getJid().asBareJid()); + packet.setFrom(conversation.getAccount().getJid()); + Element x = new Element("x"); + x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user"); + Element invite = new Element("invite"); + invite.setAttribute("to", contact.asBareJid().toString()); + x.addChild(invite); + packet.addChild(x); + return packet; + } - public MessagePacket received(Account account, MessagePacket originalMessage, ArrayList namespaces, int type) { - MessagePacket receivedPacket = new MessagePacket(); - receivedPacket.setType(type); - receivedPacket.setTo(originalMessage.getFrom()); - receivedPacket.setFrom(account.getJid()); - for (String namespace : namespaces) { - receivedPacket.addChild("received", namespace).setAttribute("id", originalMessage.getId()); - } - receivedPacket.addChild("store", "urn:xmpp:hints"); - return receivedPacket; - } + public MessagePacket received(Account account, MessagePacket originalMessage, ArrayList namespaces, int type) { + MessagePacket receivedPacket = new MessagePacket(); + receivedPacket.setType(type); + receivedPacket.setTo(originalMessage.getFrom()); + receivedPacket.setFrom(account.getJid()); + for (String namespace : namespaces) { + receivedPacket.addChild("received", namespace).setAttribute("id", originalMessage.getId()); + } + receivedPacket.addChild("store", "urn:xmpp:hints"); + return receivedPacket; + } - public MessagePacket received(Account account, Jid to, String id) { - MessagePacket packet = new MessagePacket(); - packet.setFrom(account.getJid()); - packet.setTo(to); - packet.addChild("received", "urn:xmpp:receipts").setAttribute("id", id); - packet.addChild("store", "urn:xmpp:hints"); - return packet; - } + public MessagePacket received(Account account, Jid to, String id) { + MessagePacket packet = new MessagePacket(); + packet.setFrom(account.getJid()); + packet.setTo(to); + packet.addChild("received", "urn:xmpp:receipts").setAttribute("id", id); + packet.addChild("store", "urn:xmpp:hints"); + return packet; + } - public MessagePacket sessionProposal(final JingleConnectionManager.RtpSessionProposal proposal) { - final MessagePacket packet = new MessagePacket(); + public MessagePacket sessionProposal(final JingleConnectionManager.RtpSessionProposal proposal) { + final MessagePacket packet = new MessagePacket(); packet.setType(MessagePacket.TYPE_CHAT); //we want to carbon copy those - packet.setTo(proposal.with); - packet.setId(JingleRtpConnection.JINGLE_MESSAGE_PROPOSE_ID_PREFIX +proposal.sessionId); - final Element propose = packet.addChild("propose", Namespace.JINGLE_MESSAGE); - propose.setAttribute("id", proposal.sessionId); - propose.addChild("description", Namespace.JINGLE_APPS_RTP); - packet.addChild("request", "urn:xmpp:receipts"); - return packet; - } + packet.setTo(proposal.with); + packet.setId(JingleRtpConnection.JINGLE_MESSAGE_PROPOSE_ID_PREFIX + proposal.sessionId); + final Element propose = packet.addChild("propose", Namespace.JINGLE_MESSAGE); + propose.setAttribute("id", proposal.sessionId); + propose.addChild("description", Namespace.JINGLE_APPS_RTP); + packet.addChild("request", "urn:xmpp:receipts"); + packet.addChild("store", "urn:xmpp:hints"); + return packet; + } - public MessagePacket sessionRetract(final JingleConnectionManager.RtpSessionProposal proposal) { - final MessagePacket packet = new MessagePacket(); + public MessagePacket sessionRetract(final JingleConnectionManager.RtpSessionProposal proposal) { + final MessagePacket packet = new MessagePacket(); packet.setType(MessagePacket.TYPE_CHAT); //we want to carbon copy those - packet.setTo(proposal.with); - final Element propose = packet.addChild("retract", Namespace.JINGLE_MESSAGE); - propose.setAttribute("id", proposal.sessionId); - propose.addChild("description", Namespace.JINGLE_APPS_RTP); - return packet; - } + packet.setTo(proposal.with); + final Element propose = packet.addChild("retract", Namespace.JINGLE_MESSAGE); + propose.setAttribute("id", proposal.sessionId); + propose.addChild("description", Namespace.JINGLE_APPS_RTP); + packet.addChild("store", "urn:xmpp:hints"); + return packet; + } - public MessagePacket sessionReject(final Jid with, final String sessionId) { - final MessagePacket packet = new MessagePacket(); - packet.setType(MessagePacket.TYPE_CHAT); //we want to carbon copy those - packet.setTo(with); - final Element propose = packet.addChild("reject", Namespace.JINGLE_MESSAGE); - propose.setAttribute("id", sessionId); - propose.addChild("description", Namespace.JINGLE_APPS_RTP); - return packet; - } + public MessagePacket sessionReject(final Jid with, final String sessionId) { + final MessagePacket packet = new MessagePacket(); + packet.setType(MessagePacket.TYPE_CHAT); //we want to carbon copy those + packet.setTo(with); + final Element propose = packet.addChild("reject", Namespace.JINGLE_MESSAGE); + propose.setAttribute("id", sessionId); + propose.addChild("description", Namespace.JINGLE_APPS_RTP); + packet.addChild("store", "urn:xmpp:hints"); + return packet; + } } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index c37155772..908166de4 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -31,6 +31,7 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.ReadByMarker; import eu.siacs.conversations.entities.ReceiptRequest; +import eu.siacs.conversations.entities.RtpSessionStatus; import eu.siacs.conversations.http.HttpConnectionManager; import eu.siacs.conversations.http.P1S3UrlStreamHandler; import eu.siacs.conversations.services.MessageArchiveService; @@ -73,6 +74,11 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece return safeToExtract ? extractStanzaId(packet, by) : null; } + private static String extractStanzaId(Account account, Element packet) { + final boolean safeToExtract = account.getXmppConnection().getFeatures().stanzaIds(); + return safeToExtract ? extractStanzaId(packet, account.getJid().asBareJid()) : null; + } + private static String extractStanzaId(Element packet, Jid by) { for (Element child : packet.getChildren()) { if (child.getName().equals("stanza-id") @@ -829,17 +835,56 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (!isTypeGroupChat) { for (Element child : packet.getChildren()) { if (Namespace.JINGLE_MESSAGE.equals(child.getNamespace()) && JINGLE_MESSAGE_ELEMENT_NAMES.contains(child.getName())) { - //TODO in this case we probably only want to send receipts for live messages - //as soon as it comes from MAM it is probably too late anyway - if (!account.getJid().asBareJid().equals(from.asBareJid())) { - processMessageReceipts(account, packet, query); + final String action = child.getName(); + if (query == null) { + if (!account.getJid().asBareJid().equals(from.asBareJid())) { + processMessageReceipts(account, packet, query); + } + if (serverMsgId == null) { + serverMsgId = extractStanzaId(account, packet); + } + mXmppConnectionService.getJingleConnectionManager().deliverMessage(account, packet.getTo(), packet.getFrom(), child, serverMsgId, timestamp); + } else if (query.isCatchup()) { + final String sessionId = child.getAttribute("id"); + if (sessionId == null) { + break; + } + if ("propose".equals(action)) { + final Element description = child.findChild("description"); + final String namespace = description == null ? null : description.getNamespace(); + if (Namespace.JINGLE_APPS_RTP.equals(namespace)) { + final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), false, false); + final Message message = new Message( + c, + status, + Message.TYPE_RTP_SESSION, + sessionId + ); + message.setServerMsgId(serverMsgId); + message.setTime(timestamp); + message.setBody(new RtpSessionStatus(false, 0).toString()); + c.add(message); + mXmppConnectionService.databaseBackend.createMessage(message); + } + + } else if ("proceed".equals(action)) { + //status needs to be flipped to find the original propose + final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), false, false); + final int s = packet.fromAccount(account) ? Message.STATUS_RECEIVED : Message.STATUS_SEND; + final Message message = c.findRtpSession(sessionId, s); + if (message != null) { + message.setBody(new RtpSessionStatus(true, 0).toString()); + if (serverMsgId != null) { + message.setServerMsgId(serverMsgId); + } + message.setTime(timestamp); + mXmppConnectionService.updateMessage(message, true); + } else { + Log.d(Config.LOGTAG, "unable to find original rtp session message for received propose"); + } + + } } - //TODO only live propose messages should get processed that way; however we may want to deliver 'accept' and 'reject' to stop ringing - mXmppConnectionService.getJingleConnectionManager().deliverMessage(account, packet.getTo(), packet.getFrom(), child, serverMsgId, timestamp); - - - //TODO for queries we might want to process 'propose' and 'proceed' - //TODO propose will trigger a 'missed call' entry; 'proceed' might update that to a non missed call break; } } 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 de1edf97c..3cfb2b15c 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleRtpConnection.java @@ -494,7 +494,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web if (from.equals(id.with)) { if (transition(State.RETRACTED)) { xmppConnectionService.getNotificationService().cancelIncomingCallNotification(); - Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": session with " + id.with + " has been retracted"); + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": session with " + id.with + " has been retracted (serverMsgId="+serverMsgId+")"); if (serverMsgId != null) { this.message.setServerMsgId(serverMsgId); } @@ -776,7 +776,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web messagePacket.setType(MessagePacket.TYPE_CHAT); //we want to carbon copy those messagePacket.setTo(to); messagePacket.addChild(action, Namespace.JINGLE_MESSAGE).setAttribute("id", id.sessionId); - Log.d(Config.LOGTAG, messagePacket.toString()); + messagePacket.addChild("store", "urn:xmpp:hints"); xmppConnectionService.sendMessagePacket(id.account, messagePacket); }